Region Allocation
You can create a new object on the heap using one of a few kinds of expression:
new
expr evaluates expr, places the result into the heap, and returns a pointer to the result. It is roughly equivalent tot @ temp = malloc(sizeof(t)); // where t is the type of expr *temp = _ expr_;
For example,
new 17
allocates space for an integer on the heap, initializes it to 17, and returns a pointer to the space. For another example, if we have declaredstruct Pair { int x; int y; };
then
new Pair(7,9)
allocates space for two integers on the heap, initializes the first to 7 and the second to 9, and returns a pointer to the first.new
array-initializer allocates space for an array, initializes it according to array-initializer, and returns a pointer to the first element. For example,let x = new { 3, 4, 5 };
declares a new array containing 3, 4, and 5, and initializes
x
to point to the first element. More interestingly,new { for _ identifier_ < _ expr_1 : _ expr_2 }
is roughly equivalent to
unsigned int sz = _ expr_1; t @ temp = malloc(sz * sizeof(t2)); // where t is the type of expr for (int _ identifier_ = 0; _ identifier_ < sz; _ identifier_++) temp[_ identifier_] = _ expr_2;
That is, expr1 is evaluated first to get the size of the new array, the array is allocated, and each element of the array is initialized by the result of evaluating expr2. expr2 may use identifier, which holds the index of the element currently being initialized.
For example, this function returns an array containing the first n positive even numbers:
int *@fat n_evens(int n) { return new {for next < n : 2*(next+1)}; }
Note that:
- expr1 is evaluated exactly once, while expr2 is evaluated expr1 times.
- expr1 might evaluate to 0.
- expr1 might evaluate to a negative number. If so, it is implicitly converted to a very large unsigned integer; the allocation is likely to fail due to insufficient memory. Currently, this will cause a crash!!
- Currently, for array initializers are the only way to create an object whose size depends on run-time data.
malloc(sizeof(
type))
. Returns a@notnull
pointer to an uninitialized value of type type.malloc(n*sizeof(
type))
ormalloc(sizeof(
type)*n)
. The type must be a bits-only type (i.e., cannot contain pointers, tagged unions, zero-terminated values, etc.) Ifn
is a compile-time constant expression, returns a@thin
pointer with@numelts(n)
. Ifn
is not a compile-time constant, returns a@fat
pointer to the sequence ofn
uninitialized values.calloc(n,sizeof(
type))
. Similar to themalloc
case above, but returns memory that is zero’d. Therefore,calloc
supports types that are bits-only or zero-terminated.malloc(e)
wheree
is an expression not of one of the above forms. Ife
is constant, returns achar *@numelts(e)@nozeroterm
otherwise returns a char*@fat@nozeroterm
.
Objects within regions can be created using the following analogous expressions.
rnew(
identifier)
exprrnew(
identifier)
array-initializerrmalloc(
identifier,sizeof(
type))
rmalloc(
identifier,n*sizeof(
type))
rmalloc(
identifier,sizeof(
type)*n)
rmalloc(
identifier,e))
rcalloc(
identifier,n,sizeof(
type))
Note that new
, malloc
, calloc
, rnew
, rmalloc
and rcalloc
are keywords.
Here, the first argument specifies a region handle. The Cyclone library has a global variable Core::heap_region which is a handle for the heap region. So, for example, rnew (heap_region) expr allocates memory in the heap region which is initialized with expr. Moreover, new expr can be replaced with rnew(heap_region) expr.
The only way to create an object in a stack region is declaring it as
a local variable. Cyclone does not currently support salloc
; use a
lexical region instead.